#include "PAL.h"
#include "OSProc.h"
#include "MutexLock.h"
#include "structure.h"
#include "BasicMatic.h" 


/* EDMA instance related macros. */
#define DMA_COMPL_ISR_RETRY		(10u)
#define DMA_ERR_ISR_RETRY		(10u)

#define DMA_XFER_COMPLETE                   (0u)
#define DMA_CC_DMA_EVT_MISS                 (1u)
#define DMA_CC_QDMA_EVT_MISS                (2u)

extern "C"{
//HAL hardware-interface
extern void DMA_INIT();
extern void DMA_REQUEST(unsigned int channel);
extern void DMA_SETPARAM(unsigned int channel,_DMAPar* para);
extern void DMA_ENABLE_TRANSFER(unsigned int channel,unsigned int mode);
extern void DMA_DISABLE_TRANSFER(unsigned int channel,unsigned int mode);
extern void DMA_FREE_CHANNEL(unsigned int channel,unsigned int mode);
extern unsigned int DMA_GETINTSTATE(unsigned int bg_channel);	//return a 32-bit Interrupt state after the bg-channel
extern void DMA_CLEARINTSTATE(unsigned int channel);		//the interrupt of the 'channel' be cleared
//

}

namespace PAL
{

volatile void (*DMACallBack[DMA_CHANNEL_NUM])(unsigned int,unsigned int);
unsigned int DMAMode[DMA_CHANNEL_NUM];
static volatile _mlock	DMALocker = {NULL,NULL};
volatile unsigned int DMAOwner[DMA_CHANNEL_NUM];

typedef struct DMAPAR {
        /** OPT field of PaRAM Set */
        unsigned int opt;

        /**
         * \brief Starting byte address of Source
         * For FIFO mode, srcAddr must be a 256-bit aligned address.
         */
        unsigned int srcAddr;

        /**
         * \brief Number of bytes in each Array (ACNT)
         */
        unsigned short aCnt;

        /**
         * \brief Number of Arrays in each Frame (BCNT)
         */
        unsigned short bCnt;

        /**
         * \brief Starting byte address of destination
         * For FIFO mode, destAddr must be a 256-bit aligned address.
         * i.e. 5 LSBs should be 0.
         */
        unsigned int destAddr;

        /**
         * \brief Index between consec. arrays of a Source Frame (SRCBIDX)
         */
        short  srcBIdx;

        /**
         * \brief Index between consec. arrays of a Destination Frame (DSTBIDX)
         */
        short  destBIdx;

        /**
         * \brief Address for linking (AutoReloading of a PaRAM Set)
         * This must point to a valid aligned 32-byte PaRAM set
         * A value of 0xFFFF means no linking
         */
        unsigned short linkAddr;

        /**
         * \brief Reload value of the numArrInFrame (BCNT)
         * Relevant only for A-sync transfers
         */
        unsigned short bCntReload;

        /**
         * \brief Index between consecutive frames of a Source Block (SRCCIDX)
         */
        short  srcCIdx;

        /**
         * \brief Index between consecutive frames of a Dest Block (DSTCIDX)
         */
        short  destCIdx;

        /**
         * \brief Number of Frames in a block (CCNT)
         */
        unsigned short cCnt;

        /**
         * \brief  This field is Reserved. Write zero to this field.
         */
        unsigned short rsvd;

}_DMAPar;





unsigned int DMAGetOwner(unsigned int channel)
{
	return ((channel < DMA_CHANNEL_NUM)?DMAOwner[channel]:0);
}

int DMARequest(unsigned int channel,unsigned int (*callback)(unsigned int,unsigned int),unsigned int mark)
{
MUTEX_Lock(&DMALocker,run);
	if(DMACallBack[channel] != NULL)
	{
MUTEX_UnLock(&DMALocker,run);
		return 0;
	}
	DMAOwner[channel] = mark;
	DMACallBack[channel] = callback;
MUTEX_UnLock(&DMALocker,run);
	DMA_REQUEST(channel);
}

int DMATransferSetup(unsigned int channel,_DMAPar* dmapar,unsigned int mode)
{
MUTEX_Lock(&DMALocker,run);
	if(DMACallBack[channel] == NULL)
	{
MUTEX_UnLock(&DMALocker,run);
		return 0;
	}

////////**Transfer Virtual Space to Physical Space//////
	dmapar->srcAddr = IFDVirtualAddressToPhysicalAddress(NOW->flPage,dmapar->srcAddr);
	dmapar->destAddr = IFDVirtualAddressToPhysicalAddress(NOW->flPage,dmapar->destAddr);
	DMA_SETPARAM(channel,dmapar);
	DMA_ENABLE_TRANSFER(channel,mode);
	DMAMode[channel] = mode;
MUTEX_UnLock(&DMALocker,run);

}

int DMAFree(unsigned int channel)
{
MUTEX_Lock(&DMALocker,run);
	if(DMACallBack[channel] == NULL)
	{
MUTEX_UnLock(&DMALocker,run);
		return 0;
	}

	DMACallBack[channel] = NULL;
	DMAOwner[channel] = 0;
MUTEX_UnLock(&DMALocker,run);
	DMA_FREE_CHANNEL(channel,DMAMode[channel]);
}

int DMATransferRemove(unsigned int channel)
{
MUTEX_Lock(&DMALocker,run);
	if(DMACallBack[channel] == NULL)
	{
MUTEX_UnLock(&DMALocker,run);
		return 0;
	}
	DMA_DISABLE_TRANSFER(channel,DMAMode[channel]);
MUTEX_UnLock(&DMALocker,run);
}


void DMACompleteISR()
{

    volatile unsigned int pendingIrqs;
    volatile unsigned int isIPR = 0;

    unsigned int indexl;
    unsigned int Cnt = 0;

    indexl = 1;

    isIPR = DMA_GETINTSTATE(0);

    if(isIPR)
    {
        while ((Cnt < DMA_COMPL_ISR_RETRY)&& (indexl != 0u))
        {
            indexl = 0u;
            pendingIrqs = DMA_GETINTSTATE(0);

            while (pendingIrqs)
            {
                if((pendingIrqs & 1u))
                {
                    /**
                    * If the user has not given any callback function
                    * while requesting the TCC, its TCC specific bit
                    * in the IPR register will NOT be cleared.
                    */
                    /* here write to ICR to clear the corresponding IPR bits */

                    DMA_CLEARINTSTATE(indexl);

                    if (DMACallBack[indexl] != NULL)
                    {
                        (*DMACallBack[indexl])(indexl, DMA_XFER_COMPLETE);
                    }
                }
                ++indexl;
                pendingIrqs >>= 1u;
            }
            Cnt++;
        }
    }
}
void DMAErrorISR()
{
//Clear all the bits
}

}
